package org.EasyDevelop.Builder;

import org.EasyDevelop.Bean.Constants;
import org.EasyDevelop.Bean.FieldInfo;
import org.EasyDevelop.Bean.TableInfo;
import org.EasyDevelop.Utils.PropertiesUtils;
import org.EasyDevelop.Utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.List;
import java.util.Map;

public class ServiceImplBuilder {
    private static Logger logger = LoggerFactory.getLogger(ServiceImplBuilder.class);

    public static void execute(TableInfo tableInfo){
        File folder = new File(Constants.PATH_SERVICE_IMPL);

        if(!folder.exists()) folder.mkdirs();
        String interfaceName = tableInfo.getBeanName() + StringUtils.upperCaseFirstLetter(PropertiesUtils.getValue("package.service"));
        String className = interfaceName + StringUtils.upperCaseFirstLetter(PropertiesUtils.getValue("package.service.impl"));
        File poFile = new File(folder, className + Constants.JAVA_SUFFIX);

        OutputStream os = null;
        OutputStreamWriter osw = null;
        BufferedWriter bw = null;

        try {
            os = new FileOutputStream(poFile);
            osw = new OutputStreamWriter(os, "UTF8");
            bw = new BufferedWriter(osw);

            //package
            bw.write("package " + Constants.PACKAGE_SERVICE_IMPL + ";");
            bw.newLine();
            bw.newLine();

            //import

            //Import Mapper
            String mapperPackage = Constants.PACKAGE_MAPPER;
            String mapperName = tableInfo.getBeanName() + StringUtils.upperCaseFirstLetter(Constants.SUFFIX_MAP.get("mappers"));
            bw.write("import " + mapperPackage + "." + StringUtils.upperCaseFirstLetter(mapperName) + ";\n");


            //Import Bean and BeanQuery
            bw.write("import " + Constants.PACKAGE_PO + "." + tableInfo.getBeanName() + ";");
            bw.newLine();
            bw.write("import " + Constants.PACKAGE_QUERY + "." + tableInfo.getBeanParamName() + ";");
            bw.newLine();

            //Import List
            bw.write("import java.util.List;");
            bw.newLine();

            //Import @Service
            bw.write("import org.springframework.stereotype.Service;");
            bw.newLine();

            //Import Interface Service
            bw.write("import " + Constants.PACKAGE_SERVICE + "." + interfaceName + ";");
            bw.newLine();

            //Import PaginationResVo
            bw.write("import " + Constants.PACKAGE_ENTITY_VO_PAGINATIONRESVO + ".PaginationResVo;");
            bw.newLine();

            //Import date
            if(tableInfo.getHaveDate() || tableInfo.getHaveDateTime()){
                bw.write("import java.util.Date;");
                bw.newLine();
            }
            //Import bigDecimal
            if(tableInfo.getHaveBigDecimal()){
                bw.write("import java.math.BigDecimal;");
                bw.newLine();
            }
            //Import PageSize
            bw.write("import " + Constants.PACKAGE_ENTITY + ".baseEnum.PageSize;");
            bw.newLine();
            bw.write("import " + Constants.PACKAGE_QUERY + ".base.SimplePage;");
            bw.newLine();

            //annotation
            bw.write("@Service(\"" + StringUtils.lowerCaseFirstLetter(interfaceName) + "\")");
            bw.newLine();

            //class
            bw.write("public class " + className + " implements " + interfaceName + " {");
            bw.newLine();

            //Field
            bw.write("\tprivate final " + StringUtils.upperCaseFirstLetter(mapperName) + "<" + tableInfo.getBeanName() + ", " + tableInfo.getBeanParamName() + "> " + StringUtils.lowerCaseFirstLetter(mapperName) + ";");
            bw.newLine();
            bw.newLine();

            //Construct
            /**
             * 	public AddressesServiceImpl(AddressesService addressesService) {
             * 		this.addressesService = addressesService;
             *        }
             */
            bw.write("\tpublic " + StringUtils.upperCaseFirstLetter(className) + "(" + StringUtils.upperCaseFirstLetter(mapperName) + " " + StringUtils.lowerCaseFirstLetter(mapperName) + "){");
            bw.newLine();

            bw.write("\t\tthis." + StringUtils.lowerCaseFirstLetter(mapperName) + " = " + StringUtils.lowerCaseFirstLetter(mapperName) + ";");
            bw.newLine();

            bw.write("\t}");
            bw.newLine();


            //Method

            //list
            CommentBuilder.createMethodComment(bw,"根据条件查询列表");
            bw.write("\t@Override\n");
            bw.write("\tpublic List<" + tableInfo.getBeanName() + "> findListByParam(" + tableInfo.getBeanParamName() + " query){");
            bw.newLine();

            bw.write("\t\treturn this." + StringUtils.lowerCaseFirstLetter(mapperName) + ".selectList(query);\n");

            bw.write("\t}");
            bw.newLine();

            bw.newLine();
            //count
            CommentBuilder.createMethodComment(bw,"根据条件查询数量");
            bw.write("\t@Override\n");
            bw.write("\tpublic Long findCountByParam(" + tableInfo.getBeanParamName() + " query){");
            bw.newLine();

            bw.write("\t\treturn this." + StringUtils.lowerCaseFirstLetter(mapperName) + ".selectCount(query);\n");

            bw.write("\t}");
            bw.newLine();

            bw.newLine();

            //pageList
            CommentBuilder.createMethodComment(bw,"根据条件分页查询列表");
            bw.write("\t@Override\n");
            bw.write("\tpublic PaginationResVo<" + tableInfo.getBeanName() + "> findListByPage(" + tableInfo.getBeanParamName() + " query){");
            bw.newLine();

            bw.write("\t\tLong count = this.findCountByParam(query);\n");
            bw.write("\t\tint pageSize = query.getPageSize() == null ? PageSize.SIZE20.getSize() : query.getPageSize();\n");
            bw.write("\t\tSimplePage simplePage = new SimplePage(query.getPageNo(), pageSize, Math.toIntExact(count));\n");
            bw.write("\t\tList<" + tableInfo.getBeanName() + "> res = this.findListByParam(query);\n");
            bw.write("\t\treturn new PaginationResVo<" + tableInfo.getBeanName() + ">(query.getSimplePage().getPageNo(), query.getSimplePage().getPageSize(), query.getSimplePage().getCountTotal(), query.getSimplePage().getPageTotal(), res);\n");

            bw.write("\t}");
            bw.newLine();

            bw.newLine();
            //addBatch
            CommentBuilder.createMethodComment(bw,"批量新增");
            bw.write("\t@Override\n");
            bw.write("\tpublic Long addBatch(List<" + tableInfo.getBeanName() + "> list){");
            bw.newLine();

            bw.write("\t\treturn this." + StringUtils.lowerCaseFirstLetter(mapperName) + ".insertBatch(list);\n");

            bw.write("\t}");
            bw.newLine();

            bw.newLine();
            //add
            CommentBuilder.createMethodComment(bw,"新增");
            bw.write("\t@Override\n");
            bw.write("\tpublic Long add(" + tableInfo.getBeanName() + " bean){");
            bw.newLine();

            bw.write("\t\treturn this." + StringUtils.lowerCaseFirstLetter(mapperName) + ".insert(bean);\n");

            bw.write("\t}");
            bw.newLine();

            bw.newLine();

            //addOrUpdate
            CommentBuilder.createMethodComment(bw,"新增");
            bw.write("\t@Override\n");
            bw.write("\tpublic Long addOrUpdate(" + tableInfo.getBeanName() + " bean){");
            bw.newLine();

            bw.write("\t\treturn this." + StringUtils.lowerCaseFirstLetter(mapperName) + ".insertOrUpdate(bean);\n");

            bw.write("\t}");
            bw.newLine();

            bw.newLine();

            //addOrUpdate
            CommentBuilder.createMethodComment(bw,"新增");
            bw.write("\t@Override\n");
            bw.write("\tpublic Long addOrUpdateBatch(List<" + tableInfo.getBeanName() + "> list){");
            bw.newLine();

            bw.write("\t\treturn this." + StringUtils.lowerCaseFirstLetter(mapperName) + ".insertOrUpdateBatch(list);\n");

            bw.write("\t}");
            bw.newLine();

            bw.newLine();

            //Method By Id
            generatedIdMethods(bw,tableInfo,StringUtils.lowerCaseFirstLetter(mapperName));

            bw.write("}");
            bw.newLine();

            bw.flush();

        } catch (Exception e) {
            logger.error("创建ServiceImpl文件失败,{}",e);
        } finally {
            if(bw!=null)
                try{
                    bw.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            if(osw!=null)
                try{
                    osw.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            if(os!=null)
                try{
                    os.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
        }

    }

    private static void generatedIdMethods(BufferedWriter bw, TableInfo tableInfo, String mapperName) throws IOException {
        StringBuilder methodParams = new StringBuilder();
        StringBuilder methodParams2 = new StringBuilder();
        StringBuilder methodName = new StringBuilder();
        for (Map.Entry<String, List<FieldInfo>> entry : tableInfo.getKeyIndexMap().entrySet()) {
            List<FieldInfo> keyFieldList = entry.getValue();

            //叠加索引相关值
            Integer idx = 0;
            for (FieldInfo fieldInfo : keyFieldList) {
                methodName.append(StringUtils.upperCaseFirstLetter(fieldInfo.getPropertyName()));
                methodParams.append(
                        fieldInfo.getJavaType() + " " +
                                StringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName())
                );
                methodParams2.append(
                                StringUtils.lowerCaseFirstLetter(fieldInfo.getPropertyName())
                );
                if(idx++<keyFieldList.size()-1){
                    methodName.append("And");
                    methodParams.append(", ");
                    methodParams2.append(", ");
                }
            }

            //select
            CommentBuilder.createMethodComment(bw,"根据" + methodName + "查询");
            bw.write("\t@Override\n");
            bw.write("\tpublic " + tableInfo.getBeanName() + " getBy" + methodName.toString());
            bw.write("(");
            bw.write(methodParams.toString());
            bw.write("){");
            bw.newLine();

            bw.write("\t\treturn this." + mapperName + ".selectBy" + methodName.toString() + "(" + methodParams2 + ");\n");

            bw.write("\t}");
            bw.newLine();
            bw.newLine();

            //update
            CommentBuilder.createMethodComment(bw,"根据" + methodName + "更新");
            bw.write("\t@Override\n");
            bw.write("\tpublic Long updateBy" + methodName.toString());
            bw.write("(");
            bw.write(tableInfo.getBeanName() + " bean, ");
            bw.write(methodParams.toString());
            bw.write("){");
            bw.newLine();
            bw.write("\t\treturn this." + mapperName + ".updateBy" + methodName.toString() + "(bean," + methodParams2 + ");\n");
            bw.write("\t}");
            bw.newLine();
            bw.newLine();

            //delete
            CommentBuilder.createMethodComment(bw,"根据" + methodName + "删除");
            bw.write("\t@Override\n");
            bw.write("\tpublic Long deleteBy" + methodName.toString());
            bw.write("(");
            bw.write(methodParams.toString());
            bw.write("){");
            bw.newLine();
            bw.write("\t\treturn this." + mapperName + ".deleteBy" + methodName.toString() + "(" + methodParams2 + ");\n");
            bw.write("\t}");
            bw.newLine();
            bw.newLine();


            methodName = new StringBuilder();
            methodParams = new StringBuilder();
            methodParams2 = new StringBuilder();
        }


    }
}
